package dao;

import cn.demoncat.util.es.dao.BaseEsDao;
import cn.demoncat.util.es.util.AggregationUtil;
import cn.demoncat.util.es.util.EsUtil;
import cn.demoncat.util.es.util.QueryBuilderUtil;
import cn.demoncat.util.es.util.QueryUtil;
import cn.demoncat.util.lang.ArrayUtil;
import cn.demoncat.util.lang.StringUtil;
import cn.demoncat.util.lang.entity.MapSo;
import cn.demoncat.util.lang.entity.Pager;
import cn.demoncat.util.lang.entity.report.SidCount;
import doc.DmallSkuSearchDoc;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 商品搜索DAO - ES
 *
 * @author 延晓磊
 * @since 2022年07月28日
 */
@Component
public class DmallSkuSearchDao extends BaseEsDao<DmallSkuSearchDoc,Long> {

    /**
     * 建议列表
     *
     * @param kw    关键词：商品名称
     * @return
     *
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public List<String> suggest(String kw){
        return this.completionSuggest(kw, "title");
    }

    /**
     * 建议列表 + 统计
     *
     * @param kw    关键词：商品名称
     * @return
     *
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public List<SidCount> suggestCount(String kw){
        // 查询建议
        List<String> list = this.completionSuggest(kw, "title");
        if (list.isEmpty()) {
            return new ArrayList<>();
        }else{
            return list.parallelStream().map(o -> new SidCount(o, count(QueryUtil.match("name", o)))).collect(Collectors.toList());
        }
    }

    /**
     * 商品列表
     *
     * @param kw            关键词：商品名称
     * @param channelId     渠道ID
     * @param catId         分类ID，前缀匹配
     * @param brand         品牌名称：多个用,分隔（支持多选）
     * @param stockStatus   库存状态：0无货、1有效、2预订
     * @param sort          排序方式：10/11价格，20/21销量
     * @param pageNum
     * @param pageSize
     *
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public Pager<DmallSkuSearchDoc> findPage(String kw, String channelId, String catId, String brand, String stockStatus, String sort, Integer pageNum, Integer pageSize){
        // 排序方式
        Sort sorts = null;
        if (StringUtils.isNotBlank(sort)) {
            switch (sort) {
                case "10":
                    sorts = QueryUtil.getSort("price");
                    break;
                case "11":
                    sorts = QueryUtil.getSort("price", false);
                    break;
                case "20":
                    sorts = QueryUtil.getSort("sellNum");
                    break;
                case "21":
                    sorts = QueryUtil.getSort("sellNum", false);
                    break;
                default:
                    break;
            }
        }

        // 搜索条件 - 计分
        List<QueryBuilder> queries = new ArrayList<>();
        HighlightQuery high = null;
        if (StringUtils.isNotBlank(kw)) {
            // 关键词
            queries.add(QueryBuilderUtil.match("name", kw));
            // 高亮
            high = QueryUtil.getHigh("name");
        }
        QueryBuilder query = queries.isEmpty() ? null : queries.get(0);

        // 过滤条件 - 不计分
        List<AbstractAggregationBuilder<?>> aggs = new ArrayList<>();
        List<QueryBuilder> filters = new ArrayList<>();
        if (StringUtils.isNotBlank(channelId)) {
            // 渠道：精确匹配
            filters.add(QueryBuilderUtil.term("channelId", channelId));
        }
        if (StringUtils.isNotBlank(catId)) {
            // 分类：前缀查询
            filters.add(QueryBuilderUtil.prefix("catId",catId));
        }else{
            // 聚合
            aggs.add(AggregationUtil.terms("catAgg", "catId"));
        }
        if (StringUtils.isNotBlank(brand)) {
            // 品牌：多值匹配
            filters.add(QueryBuilderUtil.terms("brand", ArrayUtil.toObjArray(StringUtil.split(brand))));
        }else{
            // 聚合
            aggs.add(AggregationUtil.terms("brandAgg", "brand"));
        }
        if (StringUtils.isNotBlank(stockStatus)) {
            // 库存状态：精确匹配
            filters.add(QueryBuilderUtil.term("stockStatus", stockStatus));
        }
        QueryBuilder filter = filters.isEmpty() ? null : QueryBuilderUtil.and(filters);

        // 分页查询
        Pager<DmallSkuSearchDoc> page = this.findPage(QueryUtil.addHigh(QueryUtil.addAgg(QueryUtil.build(query, filter), aggs),high), pageNum, pageSize, sorts);

        // 高亮处理
        if (high != null) {
            List<List<String>> highs = EsUtil.getHigh(page, "name");
            List<String> title;
            for (int i = 0; i < page.getList().size(); i++) {
                title = highs.get(i);
                if (CollectionUtils.isEmpty(title)) {
                    page.getList().get(i).setTitle(page.getList().get(i).getName());
                }else{
                    page.getList().get(i).setTitle(title.get(0));
                }
            }
        }

        // 分组聚合
        if (aggs.isEmpty()) {
            page.setExt(MapSo.EMPTY);
        }else{
            MapSo map = MapSo.getInstance();
            // 分类
            if (StringUtils.isNotBlank(catId)) {
                // 搜索条件：catId
                map.put("catId", catId);
            }else{
                // 聚合结果：[{id:catId,count}]
                map.put("catList", EsUtil.getAgg(page, "catAgg").stream().map(o -> new SidCount(o.getKeyAsString(), o.getDocCount())).sorted(Comparator.comparing(SidCount::getCount).reversed()).collect(Collectors.toList()));
            }
            // 品牌
            if (StringUtils.isNotBlank(brand)) {
                // 搜索条件：catId
                map.put("brand", brand);
            }else{
                // 聚合结果：[{id:brand,count}]
                map.put("brandList", EsUtil.getAgg(page, "brandAgg").stream().map(o -> new SidCount(o.getKeyAsString(), o.getDocCount())).sorted(Comparator.comparing(SidCount::getCount).reversed()).collect(Collectors.toList()));
            }
            page.setExt(map);
        }
        return page;
    }



}
